const schedule = require('node-schedule')
const { UnDownloadedBook } = require('../db')
const log4js = require('../config/log4js')
const log = log4js.getLogger('schedule')
const error = log4js.getLogger('error')
const orgBookSources = require('../BookSources')

const BookSources = {}

async function initBookSources () {
  // 初始书源是以数组的形式存在的，这里转化为键值对形式，方便后面调用
  for (let i = 0; i < orgBookSources.length; i++) {
    const bs = orgBookSources[i]
    await bs.initBS()
    BookSources[bs.name] = bs
  }
}

const jobFn = async () => {
  log.info(`schedule start...`)

  // 从库中取出一本未下载的书籍
  const unDownloadedBook = await UnDownloadedBook.findOne({}, {}, {
    sort: {
      createTime: 1
    }
  })
  if (!unDownloadedBook) {
    log.info('there is no more task to execute...')
    return
  }
  log.info('start download book, book is:')
  log.info(unDownloadedBook._doc)

  // 根据书源类型取得书源对象
  const bookSource = BookSources[unDownloadedBook.type]
  if (!bookSource) {
    log.info(`书源 ${unDownloadedBook.type} 已不存在, 请尽快处理`)
  }

  // unDownloadedBook.bookOptions是以Map形式存储的，这里转换为Object
  const bookOptionsMap = unDownloadedBook.bookOptions
  bookOptionsMap.set('bookId', unDownloadedBook.bookId)
  const bookOptions = {}
  bookOptionsMap.forEach((v, k) => {
    bookOptions[k] = v
  })

  // 执行preDownload方法
  const preDownloadOptions = await bookSource.preDownload(bookOptions)

  if (preDownloadOptions) {
    // 执行downloadBook方法
    let downloadBookOptions
    try {
      downloadBookOptions = await bookSource.downloadBook(preDownloadOptions)
    } catch (err) {
      error.error(err)
      // 下载失败有可能时Cookie过期导致，这里刷新Cookie再次尝试
      await bookSource.attachCookie()
      downloadBookOptions = await bookSource.downloadBook(preDownloadOptions)
    }
    if (downloadBookOptions) {
      // 执行postDownload方法
      await bookSource.postDownload(downloadBookOptions)
      await unDownloadedBook.remove()
    }
  }

  log.info(`schedule end...`)
}

const wrappedJobFn = async () => {
  try {
    await jobFn()
  } catch (err) {
    error.error('jobFn error:')
    error.error(err)
  }
}

let job

initBookSources().then(() => {
  // https://www.npmjs.com/package/node-schedule
  job = schedule.scheduleJob('*/10 * * * *', wrappedJobFn)
  // job.invoke()
  log.info(`scheduling...`)
})

module.exports = job
